package com.portal.framework.dao;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.util.PropertyFilter;

import com.portal.framework.common.CommonUtil;
import com.portal.framework.common.lang.NameValue;
import com.portal.framework.dao.annotation.PropertySearchType;
import com.portal.framework.dao.annotation.SearchAnnotation;
import com.portal.framework.dao.annotation.SearchProp;
import com.portal.framework.util.ClassUtil;
import com.portal.framework.util.CollectionUtils;
import com.portal.framework.util.JsonUtil;
import com.portal.framework.util.StringUtils;

/**
 * 搜索表单的基类,在要搜索的属性上加上 @ SearchProp 注释,<BR>
 *                    该属性将自动为搜索条件,要确认属性名与搜索条件属性名一致
 * @author 卢烁波
 * @date 2007-3-10
 */
public class BaseSearchForm implements ISearchForm, JsonSupport {
	private Set<SearchCondition> conditions;
	private Set<SearchCondition> conditionsForAnd;
	
	private static final long serialVersionUID = 1L;

	public static final int DEFAULT_PAGE_SIZE = 15;

	public final static int WHERE_FLAG = 0;// 有查询条件


	private String jsonWhere; // 在页面上接受searchForm的查询条件
	
	private Integer selStruts; //查询状态，0代表查询，1代表编辑，2代表删除

	private List<PropertyCondition> propertyConditions;

	@SearchAnnotation
	private int flag = 0;// 有查询条件


	@SearchAnnotation
	private boolean distinct = false;// 是否添加 distinct 默认为false

	private int page;
	
	private int currentPage; //为增删改服务的变更
	
	// 每页显示的记录数
	@SearchAnnotation
	private int pageSize = DEFAULT_PAGE_SIZE;

	// 共显示的记录数,用于只要得到前多少条记录(如排行榜)
	private int maxResult = MAX_RESULT;

	// 是否需要分页,如果为false则PagerReuslt的分页信息对象将为null
	@SearchAnnotation
	private boolean isNeedPage = true;

	private JoinMode joinMode = JoinMode.INNER_JOIN;

	/**
	 * 排序信息
	 */
	private List<NameValue<SearchOrder>> orderBys;

	// 可以包含GroupBy信息
	// 返回信息 (select)
	private List<ProjectionSearchType> projections;

	private String hql;

	public void setHql(String hql) {
		this.hql = hql;
	}

	public List<NameValue<SearchOrder>> getOrderBys() {
		return orderBys;
	}

	public void setOrderBys(List<NameValue<SearchOrder>> orderBys) {
		this.orderBys = orderBys;
	}

	public int getPage() {
		if(page<=0){
			page=1;
		}
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getMaxResult() {
		return maxResult;
	}

	public void setMaxResult(int size) {
		this.maxResult = size;
	}

	public void addOrderBy(NameValue<SearchOrder> orderBy) {
		if (this.orderBys == null) {
			orderBys = new ArrayList<NameValue<SearchOrder>>();
		}
		orderBys.add(orderBy);
	}

	public void addOrderBy(String fieldName, SearchOrder orderBy) {
		this.addOrderBy(new NameValue<SearchOrder>(fieldName, orderBy));
	}

	public String getHql() {
		return hql;
	}

	/**
	 * @param propName 字段名

	 * @param projectionType 返回值类型,可以为如果类型为group by类型,则将添加一个group by的返回值

	 * @param alias 别名
	 */
	public void addProjectSearchType(String propName,
			ProjectionType projectionType, String alias) {
		if (projections == null) {
			projections = new ArrayList<ProjectionSearchType>();
		}
		projections.add(new ProjectionSearchType(propName, projectionType,
				alias));
	}

	public void addProjectSearchType(ProjectionSearchType projectionSearchType) {
		if (projections == null) {
			projections = new ArrayList<ProjectionSearchType>();
		}
		projections.add(projectionSearchType);
	}

	public List<ProjectionSearchType> getProjectionType() {
		if (CollectionUtils.empty(projections)) {
			return null;
		}
		return projections;
	}

	public boolean isNeedPage() {
		return isNeedPage;
	}

	public void setNeedPage(boolean isNeedPage) {
		this.isNeedPage = isNeedPage;
	}
	
	public JoinMode getJoinMode() {
		return joinMode;
	}

	public void setJoinMode(JoinMode joinMode) {
		this.joinMode = joinMode;
	}

	public int getFlag() {
		return flag;
	}

	public void setFlag(int flag) {
		this.flag = flag;
	}

	public ISearchForm fromJsonString() {
		fromJsonString(this.getJsonWhere());
		return this;
	}

	public <T extends ISearchForm> T fromJsonString(Class<T> retClass) {
		fromJsonString(this.getJsonWhere());
		return retClass.cast(this);
	}

	public void fromJsonString(String jsonString) {
		if (StringUtils.emptyTrimed(jsonString)) {
			return;
		}

		ISearchForm form = getFromJsonStringByClass(jsonString, getClass());
		// TODO 只把搜索属性copy
		int page = this.getPage();
		CommonUtil.copyProperties(this, form);
		this.page = page;
	}

	public String toJsonString() {
		PropertyFilter filter = new AnnotationSearchFormFilter();
		JsonConfig config = new JsonConfig();
		config.setJsonPropertyFilter(filter);
		return JSONObject.fromObject(this, config).toString();
	}

	public static ISearchForm getFromJsonString(String jsonString) {
		return getFromJsonStringByClass(jsonString, null);
	}

	@SuppressWarnings("unchecked")
	public static <T extends BaseSearchForm> T getFromJsonStringByClass(
			String jsonString, Class<T> searchFormClass) {

		PropertyFilter filter = new SearcFormFilter(searchFormClass);
		JsonConfig config = new JsonConfig();
		config.setJsonPropertyFilter(filter);
		// JSONUtils.getMorpherRegistry().registerMorpher(JsonUtil.getObjectFromJsonString(jsonString,
		// clazz))

		// JSONObject o = JSONObject.fromObject(jsonString);
		// JSONObject o = JSONObject.fromObject(jsonString, config);
		// return (T) JSONObject.toBean(o, searchFormClass);
		return JsonUtil.getObjectFromJsonString(jsonString, searchFormClass,
				config);
	}

	@SuppressWarnings("unchecked")
	public static <T extends ISearchForm> ISearchForm getFromJsonString(
			String jsonString, T searchForm) {

		PropertyFilter filter = new SearcFormFilter(searchForm.getClass());
		JsonConfig config = new JsonConfig();
		config.setJsonPropertyFilter(filter);
		JSONObject o = JSONObject.fromObject(jsonString, config);
		return (T) JSONObject.toBean(o, searchForm, config);
	}

	private static class AnnotationSearchFormFilter implements PropertyFilter {
		public boolean apply(Object source, String name, Object value) {
			Field f = ClassUtil.getField(source.getClass(), name, null);
			if (f == null) {
				return false;
			}
			if (f.getAnnotation(SearchProp.class) != null
					|| f.getAnnotation(SearchAnnotation.class) != null) {
				return false;
			}

			return true;
		}
	}

	private static class SearcFormFilter implements PropertyFilter {
		private Class<? extends ISearchForm> searchFormClass;

		public SearcFormFilter(Class<? extends ISearchForm> searchFormClass) {
			this.searchFormClass = searchFormClass;
		}

		public boolean apply(Object source, String name, Object value) {
			if (searchFormClass == null) {
				return false;
			}
			Field f = ClassUtil.getField(searchFormClass, name, null);
			if (f == null) {
				return false;
			}

			/**
			 * 如果是日期类,并且为Null时,就不需要转换

			 */
			Class<?> type = f.getType();
			if (value instanceof String) {
				if (Date.class == type
						&& StringUtils.emptyTrimed((String) value)) {
					return true;
				}
			}

			// if (!isMatch(f)) {
			// return true;
			// }

			return false;
		}
	}

	private static boolean isMatch(Field f) {

		Class<?> type = f.getType();
		if (isMatchByType(type)) {
			return true;
		}
		if (type.isArray() && isMatchByType(type.getComponentType())) {
			return true;
		}

		return false;
	}

	private static boolean isMatchByType(Class type) {
		if (type.isPrimitive()) {
			return true;
		}

		if (ClassUtil.toPrimaryClass(type).isPrimitive()) {
			return true;
		}
		if (Date.class.isAssignableFrom(type)) {
			return true;
		}
		if (String.class.isAssignableFrom(type)) {
			return true;
		}

		return false;
	}

	public String getJsonWhere() {
		return jsonWhere;
	}

	public void setJsonWhere(String jsonWhere) {
		this.jsonWhere = jsonWhere;
	}

	public boolean isDistinct() {
		return distinct;
	}

	public void setDistinct(boolean distinct) {
		this.distinct = distinct;
	}

	public void addPropertyCondition(String property1, String property2,
			PropertySearchType propertySearchType) {
		if (propertyConditions == null) {
			propertyConditions = new ArrayList<PropertyCondition>();
		}
		propertyConditions.add(new PropertyCondition(property1, property2,
				propertySearchType));
	}

	public List<PropertyCondition> getPropertyCondition() {
		return propertyConditions;
	}

	public void addCondition(String fieldName, String nullValue,
			SearchType searchType, Object value,String orKey) {
		if (conditions == null) {
			conditions = new HashSet<SearchCondition>();
		}
		conditions.add(new SearchCondition(fieldName, nullValue, searchType,
				value,orKey));
	}

	public void addCondition(SearchCondition condition) {
		if (condition != null) {
			conditions.add(condition);
		}
	}

	public Set<SearchCondition> getConditions() {
		return conditions;
	}

	public void addCondition(String fieldName, SearchType searchType,
			Object value) {
		this.addCondition(fieldName, "", searchType, value);
	}

	public void addCondition(String fieldName, String nullValue,
			SearchType searchType, Object value) {
		this.addCondition(fieldName, "", searchType, value,null);
	}
	
	public void addConditionForAnd(String fieldName, String nullValue, SearchType searchType, Object value,String orKey){
		if (conditionsForAnd == null) {
			conditionsForAnd = new HashSet<SearchCondition>();
		}
		conditionsForAnd.add(new SearchCondition(fieldName, nullValue, searchType,value,orKey));
	}
	/**
	 * 得到动态添加的条件
	 * ((a and b and c) or (a and b and c)) 
	 * 
	 * @return
	 */
	public Set<SearchCondition> getConditionsForAnd(){
		return conditionsForAnd;
	}

	public Integer getSelStruts() {
		return selStruts;
	}

	public void setSelStruts(Integer selStruts) {
		this.selStruts = selStruts;
	}

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

}
